package net.vkits.auth.shiro.realm;

import net.vkits.auth.domain.model.Role;
import net.vkits.auth.domain.model.User;
import net.vkits.auth.domain.repository.PermissionRepository;
import net.vkits.auth.domain.repository.UserRepository;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Optional;
import java.util.Set;

/**
 * Created by ethan-liu on 16/3/14.
 */
@Transactional
public class DBRealm extends AuthorizingRealm {

    @Resource
    private UserRepository userRepository;

    @Resource
    private PermissionRepository permissionRepository;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String)principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Optional<User> userOptional = userRepository.findByUsername(username);

        // 如果User是Admin即赋予全部权限，否则赋予Roles的相关权限
        userOptional.ifPresent(user -> {
            if (user.isAdmin()) {
                permissionRepository.findAll().forEach(permission ->
                        authorizationInfo.addStringPermission(permission.getPermission()));
            } else {
                Set<Role> roles = user.getRoles();
                roles.forEach(role ->
                        role.getPermissions().forEach(permission ->
                                authorizationInfo.addStringPermission(permission.getPermission())));
            }
        });
        userOptional.orElseThrow(UnknownAccountException::new);

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String)token.getPrincipal();
        Optional<User> userOptional = userRepository.findByUsernameAndDeletedFalse(username);
        if(!userOptional.isPresent()) {
            throw new UnknownAccountException();//没找到帐号
        }
        if(Boolean.TRUE.equals(userOptional.get().isLocked())) {
            throw new LockedAccountException(); //帐号锁定
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userOptional.get().getUsername(), //用户名
                userOptional.get().getPassword(), //密码
                ByteSource.Util.bytes(userOptional.get().getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        return authenticationInfo;
    }
}
